package example;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

public class JodisClient implements Runnable{
    //服务器端的ip
    private String host;
    //服务器端的端口号
    private int port;
    //多路服用选择器
    private Selector selector;

    private SocketChannel socketChannel;

    private volatile boolean stop;


    public JodisClient(String host, int port){
        this.host = host == null ? "127.0.0.1": host;
        this.port = port;
        try {
            //初始化一个Selector，工厂方法
            selector = Selector.open();
            //初始化一个SocketChannel，工厂方法
            socketChannel = SocketChannel.open();
            //设置非阻塞模式
            socketChannel.configureBlocking(false);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }



    /**
     * 首先尝试连接服务端
     * @throws IOException
     */
    public void doConnect() throws IOException {
        if(socketChannel.connect(new InetSocketAddress(this.host,this.port))){
            System.out.println("doconnect register the read event");
            socketChannel.register(selector, SelectionKey.OP_READ);
            //执行写操作
            doWrite(socketChannel);
        }else {
            //监听连接请求
            System.out.println("doconnect register the connect event");
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
        }
    }

    public static void doWrite(SocketChannel sc) throws IOException {
        System.out.println("please input：");
        Scanner scanner = new Scanner(System.in);
        String result = scanner.nextLine();
        //构造请求消息体
        byte [] bytes = result.getBytes();
        //构造ByteBuffer
        ByteBuffer write = ByteBuffer.allocate(bytes.length);
        //将消息体写入发送缓冲区
        write.put(bytes);
        write.flip();
        //调用channel的发送方法异步发送
        sc.write(write);
        //通过hasRemaining方法对发送结果进行判断，如果消息全部发送成功，则返回true
        if(!write.hasRemaining()){
            System.out.println("send order to server successd");
        }
    }

    @Override
    public void run() {
        try {
            doConnect();
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }

        while (!stop){
            try {
                selector.select(1000);
                Set<SelectionKey> keys =  selector.selectedKeys();
                Iterator<SelectionKey> iterator =keys.iterator();
                SelectionKey key = null;
                while (iterator.hasNext()){
                    key = iterator.next();
                    iterator.remove();
                    try{
                        handle(key);
                    }catch (Exception e){
                        if(key != null){
                            key.cancel();
                            if(key.channel() != null){
                                key.channel().close();
                            }
                        }
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
                System.exit(1);
            }
        }
    }

    public  void handle(SelectionKey key) throws IOException {
        if(key.isValid()){
            SocketChannel sc = (SocketChannel) key.channel();
            if(key.isConnectable()){
                //如果连接成功，监听读请求
                if(sc.finishConnect()){
                    System.out.println("the client has connected to the server");
                    sc.register(this.selector, SelectionKey.OP_READ);
                    //向服务端发送数据
                    doWrite(sc);
                }else{
                    System.exit(1);
                }
            }

            //监听到读请求，从服务器端接受数据
            if(key.isReadable()){
                System.out.print("the client connect receive data from server：");
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                int readBytes = sc.read(byteBuffer);
                if(readBytes > 0){
                    byteBuffer.flip();
                    byte []  bytes = new byte[byteBuffer.remaining()];
                    byteBuffer.get(bytes);
                    String body = new String(bytes,"UTF-8");
                    System.out.println("now body is ："+ body);
                }else if(readBytes < 0){
                    key.cancel();
                    sc.close();
                }

                //向服务端发送数据
                doWrite(sc);
            }
        }
    }

    public static void main(String[] args) {
        int port = 6059;
        JodisClient client = new JodisClient("",port);
        new Thread(client).start();
    }
}
